package utils

import (
	"bytes"
	"crypto"
	"crypto/cipher"
	"crypto/des"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"fx_swift_schedule/api"
	"fx_swift_schedule/pkg/global"
)

//timetype RsaUtils struct {
//}

// 解密部分
func Decrypt(bean *api.Bean) (resJson []byte, errs error) {
	// 对key进行rsa私钥解密
	key := rsaDecrypt(bean)

	// 用des和key解密明文
	jsonEnc, _ := hex.DecodeString(bean.JsonEnc)
	resStr, _ := DesDecrypt(jsonEnc, key)

	fmt.Println(string(resStr))

	// 对明文公钥验签
	err := verifySign(bean, resStr)
	if err != nil {
		fmt.Println("验签失败")
	} else {
		fmt.Println("验签成功")
	}

	return resStr, err
}

func rsaDecrypt(bean *api.Bean) []byte {
	keyEnc, _ := hex.DecodeString(bean.KeyEnc)
	pri, _ := GetPrivateKey()
	pkcs1v15, _ := rsa.DecryptPKCS1v15(rand.Reader, pri, keyEnc)
	key, _ := base64.StdEncoding.DecodeString(string(pkcs1v15))
	return key
}

func verifySign(bean *api.Bean, json []byte) error {
	sign, _ := hex.DecodeString(bean.Sign)
	// blockP, _ := pem.Decode(serverPublicKey)
	publicKey, _ := GetPublicKey()

	h := crypto.Hash.New(crypto.SHA1)
	h.Write(json)
	hash := h.Sum(nil)

	err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hash, sign)
	return err
}

func generateRandomBytes(length int) ([]byte, error) {
	randomBytes := make([]byte, length)
	_, err := rand.Read(randomBytes)
	if err != nil {
		return nil, err
	}

	return randomBytes, nil
}

// 加密部分
func Encrtpt(data string, merchantNo string) (encrypt *api.Bean) {

	//priKey, pubkey := GenRsaKey()

	// 生成8字节random数组
	//random := []byte("11111111")
	random, err := generateRandomBytes(8)
	if err != nil {
		fmt.Println("Failed to generate random bytes:", err)
		return
	}
	// 对8字节数组做base64
	keyEnc := hex.EncodeToString(rsaEncrtpy(random))
	fmt.Print("keyEnc: ", keyEnc, "\n")

	// 用key初始化des 向量和key相同 加密明文 并转16进制
	jsonEnc, _ := DesEncrypt([]byte(data), random)
	fmt.Print("jsonEnc: ", jsonEnc, "\n")

	// 对明文用私钥加签 加密方式SHA-1 并转16进制
	sign := rsaSign(data)
	fmt.Print("sign: ", sign, "\n")

	bean := &api.Bean{
		MerchantNo: merchantNo,
		JsonEnc:    jsonEnc,
		KeyEnc:     keyEnc,
		Sign:       sign,
	}

	return bean
}

// DES解密
func DesDecrypt(crypted, key []byte) ([]byte, error) {
	// 根据密钥生成block
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// 根据block和初始向量生成解密算法,IV长度与block.size需要保持一致
	blockMode := cipher.NewCBCDecrypter(block, key)
	// 对密文解密
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	// 反扩充,获取原始明文
	origData = PKCS5Unpadding(origData)
	return origData, nil
}

// DES加密
func DesEncrypt(origData, key []byte) (string, error) {
	// 根据密钥生成block
	block, _ := des.NewCipher(key)

	// 根据block和初始向量生成加密算法,IV长度与block.size需要保持一致
	blockMode := cipher.NewCBCEncrypter(block, key)
	// 扩充 origData
	origData = Pkcs5Padding(origData, block.BlockSize())
	crypted := make([]byte, len(origData))
	// 对padded data加密
	blockMode.CryptBlocks(crypted, origData)
	return hex.EncodeToString(crypted), nil
}

func PKCS5Unpadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func Pkcs5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func rsaEncrtpy(random []byte) []byte {
	randomBase64 := base64.StdEncoding.EncodeToString(random)

	// 对base64Key用公钥rsa加密 并转16进制
	// block, _ := pem.Decode(pubkey)
	// pub, _ := x509.ParsePKCS1PublicKey(block.Bytes)
	pub, _ := GetPublicKey()
	keyEnc, _ := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(randomBase64))
	return keyEnc
}

func rsaSign(data string) string {
	// blo, _ := pem.Decode(priKey)
	// parsePKCS1PrivateKey, _ := x509.ParsePKCS1PrivateKey(blo.Bytes)
	parsePKCS1PrivateKey, _ := GetPrivateKey()
	h := crypto.Hash.New(crypto.SHA1)
	h.Write([]byte(data))
	hash := h.Sum(nil)

	signPKCS1v15, _ := rsa.SignPKCS1v15(rand.Reader, parsePKCS1PrivateKey, crypto.SHA1, hash)
	sign := hex.EncodeToString(signPKCS1v15)
	return sign
}

// RSA公钥私钥产生
func GenRsaKey() (prvkey, pubkey []byte) {
	// 生成私钥文件
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(err)
	}
	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
	block := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: derStream,
	}
	prvkey = pem.EncodeToMemory(block)
	publicKey := &privateKey.PublicKey
	derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		panic(err)
	}
	block = &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: derPkix,
	}
	pubkey = pem.EncodeToMemory(block)
	return
}

func GetPrivateKeyStr() string {
	privateKeyPEM := fmt.Sprintf("-----BEGIN RSA PUBLIC KEY-----\n%s\n-----END RSA PUBLIC KEY-----", global.ViperObj.GetString("ottpay.privateKeyPEM"))
	return privateKeyPEM
}

func GetPublicKeyStr() string {
	publicKeyPEM := fmt.Sprintf("-----BEGIN RSA PUBLIC KEY-----\n%s\n-----END RSA PUBLIC KEY-----", global.ViperObj.GetString("ottpay.publicKeyPEM"))
	return publicKeyPEM
}

func GetPublicKey() (*rsa.PublicKey, error) {

	return pemToRSAPublicKey(GetPublicKeyStr())
}

// 将PEM格式的公钥字符串转换为RSA公钥对象
func pemToRSAPublicKey(publicKeyPEM string) (*rsa.PublicKey, error) {
	block, _ := pem.Decode([]byte(publicKeyPEM))
	if block == nil {
		return nil, errors.New("failed to decode PEM block containing public key")
	}

	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	rsaPublicKey, ok := pubInterface.(*rsa.PublicKey)
	if !ok {
		return nil, errors.New("invalid public key type")
	}

	return rsaPublicKey, nil
}

func GetPrivateKey() (*rsa.PrivateKey, error) {

	return pemToRSAPrivateKey(GetPrivateKeyStr())

}

func pemToRSAPrivateKey(privateKeyPEM string) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode([]byte(privateKeyPEM))
	if block == nil {
		return nil, errors.New("failed to decode PEM block containing private key")
	}

	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	rsaPrivateKey, ok := key.(*rsa.PrivateKey)
	if !ok {
		return nil, errors.New("invalid private key type")
	}

	return rsaPrivateKey, nil
}
